package com.gframework.paramparse.points;


import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.gframework.datastructure.trie.WildcardTrieTree.ProcessResult;
import com.gframework.lang.IndexRange;
import com.gframework.paramparse.core.AnalyticFormatException;
import com.gframework.paramparse.core.extension.ExtParam;
import com.gframework.paramparse.core.extension.ExtParamContext;

/**
 * 这是一个基本的多段式参数的解析操作上下文实现类.
 * 
 * @since 1.0.0
 * @author Ghwolf
 * @see PointSegParamParseContext
 * @see PointSegParamParser
 * @see PointSegParserTree
 */
public class GenericPointSegParamParseContext implements PointSegParamParseContext {

	private static final Logger logger = LoggerFactory.getLogger(GenericPointSegParamParseContext.class);

	/**
	 * 参数前缀，不能为null或空字符串
	 */
	private String prefix = "#{";
	/**
	 * 参数后缀，不能为null或空字符串
	 */
	private String suffix = "}";

	/**
	 * 参数解析器存储树
	 */
	private PointSegParserTree pointSegParserTree;
	/**
	 * 参数解析器集合
	 */
	private PointSegParamParser[] paramParsers;

	/**
	 * @param paramParsers 参数解析器集合
	 */
	public GenericPointSegParamParseContext(PointSegParamParser[] paramParsers) {
		this.paramParsers = paramParsers;
		PointSegParamUtils.init(this);
		this.pointSegParserTree = this.buildParserTree(this.paramParsers);
		if (logger.isDebugEnabled()) {
			logger.debug("当前参数环境解析器格式如下：\n{}", this.pointSegParserTree.getFormatLeaf());
		}
	}

	@Override
	public String parse(String str, ExtParam extParam) {
		if (this.pointSegParserTree == null) {
			throw new ParserTreeInitException("GenericWildCardParamParseContext还没有初始化！");
		}
		if (StringUtils.isEmpty(str)) {
			return "";
		}
		int prefixLength = this.prefix.length();
		int suffixLength = this.suffix.length();
		int start = 0;

		int prefixIndex = str.indexOf(this.prefix);
		if (prefixIndex == -1) {
			return str ;
		}
		StringBuilder sb = new StringBuilder((int) (str.length() * 1.2));
		do {
			int suffixIndex = str.indexOf(this.suffix, prefixIndex + prefixLength);
			if (suffixIndex == -1) break;
			sb.append(str.substring(start, prefixIndex));
			// 寻找下一个字符串中的参数
			String param = str.substring(prefixIndex + prefixLength, suffixIndex);
			ProcessResult<PointSegParamParser> parser = this.getParser(param);

			String paramValue = null;
			if (parser.getValue() != null) {
				paramValue = parser.getValue().parse(param, parser.getWildcardParam(), extParam).orElse(null);
			}
			
			if (StringUtils.isNotEmpty(paramValue)) {
				sb.append(paramValue);
			}
			start = suffixIndex + suffixLength;
			prefixIndex = str.indexOf(this.prefix, start);
		} while(prefixIndex != -1);
		if (start < str.length()) {
			sb.append(str.substring(start));
		}
		return sb.toString();
	}
	
	@Override
	public String parse(String str) {
		return this.parse(str,ExtParamContext.getEmptyExtParam());
	}

	@Override
	public int nextPrefix(String str, int formIndex) {
		if (str == null) return -1 ;
		return str.indexOf(this.prefix,formIndex);
	}

	@Override
	public int nextSuffix(String str, int formIndex) {
		if (str == null) return -1 ;
		return str.indexOf(this.suffix,formIndex);
	}

	@Override
	public IndexRange next(String str, int formIndex) {
		if (str == null) return IndexRange.NON_RANGE;
		
		int start = this.nextPrefix(str,formIndex);
		if (start < 0) return IndexRange.NON_RANGE;
		
		int end = this.nextSuffix(str, start + this.prefix.length());
		if (end < 0) return IndexRange.NON_RANGE;
		
		return new IndexRange(start,end);
	}
	
	@Override
	public int nextPrefix(String str) {
		return this.nextPrefix(str,0);
	}

	@Override
	public int nextSuffix(String str) {
		return this.nextSuffix(str,0);
	}

	@Override
	public IndexRange next(String str) {
		return this.next(str,0);
	}
	
	
	@Override
	public int indexOfIgnoreParam(String source, int ch) {
		return this.indexOfIgnoreParam(source, ch,0);
	}

	@Override
	public int indexOfIgnoreParam(String source, int ch, int formIndex) {
		if (source == null || formIndex >= source.length()) return -1;
		for (int form = formIndex ; form < source.length() ; ) {
			int prefixIndex = this.nextPrefix(source,form);
			if (prefixIndex == -1) {
				return source.indexOf(ch,form);
			}
			int suffixIndex = this.nextSuffix(source,prefixIndex + this.prefix.length());
			if (suffixIndex == -1) {
				return source.indexOf(ch,form);
			}
			int searchIndex = source.indexOf(ch,form);
			if (searchIndex == -1) {
				return -1;
			} else if (searchIndex >= prefixIndex && searchIndex <= suffixIndex) {
				form = suffixIndex + this.suffix.length();
			} else {
				return searchIndex ;
			}
		}
		return -1 ;
	}
	
	@Override
	public int indexOfIgnoreParam(String source, String str) {
		return this.indexOfIgnoreParam(source, str,0);
	}

	@Override
	public int indexOfIgnoreParam(String source, String str, int formIndex) {
		if (source == null) return -1;
		if (str == null) return -1 ;
		if (formIndex >= source.length()) {
			return str.length() == 0 ? source.length() : -1 ;
		}
		for (int form = formIndex ; form < source.length() ; ) {
			int prefixIndex = this.nextPrefix(source,form);
			if (prefixIndex == -1) {
				return source.indexOf(str,form);
			}
			int suffixIndex = this.nextSuffix(source,prefixIndex + this.prefix.length());
			if (suffixIndex == -1) {
				return source.indexOf(str,form);
			}
			int searchIndex = source.indexOf(str,form);
			if (searchIndex == -1) {
				return -1;
			} else if (searchIndex >= prefixIndex && searchIndex <= suffixIndex) {
				form = suffixIndex + this.suffix.length();
			} else {
				return searchIndex ;
			}
		}
		return -1 ;
	}
	
	/**
	 * 验证解析格式是否正确，如果不正确，则抛出异常. 参数不能含有表尾标记
	 * <ol>
	 * <li>不能包含参数尾部标记</li>
	 * <li>不能出现连续的点，例如".."</li>
	 * <li>不能出现连续的*，例如"**"</li>
	 * <li>*周围不能紧挨着其他字符，例如"*a"或"a*"</li>
	 * <li>不能以分隔符开头和结尾</li>
	 * </ol>
	 * 
	 * @param analyticFormat 验证格式异常
	 * @throws AnalyticFormatException 解析格式不合法
	 */
	public void assertFormatCorrectly(String analyticFormat) throws AnalyticFormatException {
		if (analyticFormat == null || analyticFormat.length() == 0) {
			throw new AnalyticFormatException("未指定解析格式！");
		}
		if (analyticFormat.charAt(0) == '.' || analyticFormat.charAt(analyticFormat.length() - 1) == '.') {
			throw new AnalyticFormatException("参数不能以分隔符开头或结尾：" + analyticFormat);
		}
		int length = analyticFormat.length();
		char suffixFirstChar = this.suffix.charAt(0);
		for (int x = 0; x < length; x ++) {
			char c = analyticFormat.charAt(x);
			if (c == '.') {
				if (x != length - 1 && analyticFormat.charAt(x + 1) == '.') {
					throw new AnalyticFormatException("存在连续的分隔符，不应该存在连续的分隔符，通配符：" + analyticFormat);
				}
			} else if (c == '*') {
				boolean isFrontNotPoint = x != 0 && analyticFormat.charAt(x - 1) != '.';
				boolean isBehindNotPoint = x != length - 1 && analyticFormat.charAt(x + 1) != '.';
				if (isFrontNotPoint || isBehindNotPoint) {
					throw new AnalyticFormatException("通配符不能和其他字符连用，只能够单独存在：" + analyticFormat);
				}
			} else if (c == suffixFirstChar && this.startsWithBegin(analyticFormat, this.suffix, x)) {
				throw new AnalyticFormatException("参数解析格式中不允许出现[" + this.suffix + "]结尾标记：" + analyticFormat);
			}
		}
	}

	/**
	 * 判断指定字符串从某个位置开始往后是否是以另一个字符串开头。
	 * 
	 * @param source 原始字符串，不能是null或空字符串
	 * @param eqStr 要进行判断匹配的字符串，不能是null或空字符串
	 * @param start 从原始字符串哪个位置开始判断
	 * @return 如果匹配相同返回true，如果参数为null或不相同，则返回false
	 */
	private boolean startsWithBegin(String source, String eqStr, int start) {
		if (eqStr.length() + start > source.length()) {
			return false;
		}
		for (int x = 0; x < eqStr.length(); x ++) {
			if (eqStr.charAt(x) != source.charAt(x + start)) {
				return false;
			}
		}
		return true;
	}

	@Override
	public ProcessResult<PointSegParamParser> getParser(String param) {
		if (this.pointSegParserTree == null) {
			throw new ParserTreeInitException("GenericWildCardParamParseContext还没有初始化！");
		}
		return this.pointSegParserTree.find(param);
	}

	@Override
	public String getParamPrefix() {
		return this.prefix;
	}

	@Override
	public String getParamSuffix() {
		return this.suffix;
	}

	/**
	 * 构建一个参数解析器存储树
	 */
	private PointSegParserTree buildParserTree(PointSegParamParser[] paramParsers) {
		PointSegParserTree tree = new PointSegParserTree();
		for (PointSegParamParser par : paramParsers) {
			String analy = par.initAnalyticFormat();
			this.assertFormatCorrectly(analy);
			tree.createNode(analy, par);
		}
		return tree;
	}

	@Override
	public int prefixLength() {
		return this.prefix.length();
	}

	@Override
	public int suffixLength() {
		return this.suffix.length();
	}


}
